package com.bangcommunity.bbframe.monitor.collector;

import com.bangcommunity.bbframe.monitor.LogContext;
import com.bangcommunity.bbframe.monitor.LogContextHelper;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author tanghc
 * @date 18/1/30
 */
public class StatisticCollector {
    private final static ConcurrentMap<String, AtomicReference<StatisticBean>> statisticsMap = new ConcurrentHashMap<>();

    public static void collect(String key, StatisticBaseBean changes) {

        AtomicReference<StatisticBean> reference = statisticsMap.get(key);
        if (reference == null) {
            statisticsMap.putIfAbsent(key, new AtomicReference<>());
            reference = statisticsMap.get(key);
        }
        StatisticBean current;
        StatisticBean update = new StatisticBean();
        do {
            current = reference.get();
            if (current == null) {
                update.collectFirst(changes);
            } else {
                update.collect(changes);
            }
        } while (!reference.compareAndSet(current, update));
    }

    public static void collect(String mkey, StatisticStateEnum stateEnum, Object result, Throwable throwable) {

        AtomicLong concurrent = ConcurrentCountHelper.getConcurrent(mkey);
        concurrent.decrementAndGet();
        LogContext logContext = LogContextHelper.getLogContext(mkey);
        if (null != logContext) {
            StatisticBaseBean changes = new StatisticBaseBean();
            switch (stateEnum) {
            case succ:
                changes.setSuccess(1);
                break;
            case fail:
                changes.setFail(1);
                break;
            case exception:
                changes.setException(1);
                break;
            }
            changes.setElapsedNano(System.nanoTime() - logContext.getStartTimeNano());
            changes.setConcurrent(concurrent.get());
            collect(mkey, changes);
        }
    }
}
